package cn.kgc.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.kgc.entity.Depts;
import cn.kgc.entity.Roles;
import cn.kgc.entity.RouterVo;
import cn.kgc.entity.Users;
import cn.kgc.form.UsersAddForm;
import cn.kgc.form.UsersUpdateForm;
import cn.kgc.service.DeptsService;
import cn.kgc.service.MenusService;
import cn.kgc.service.RolesService;
import cn.kgc.service.UsersService;
import cn.kgc.util.Pager;
import cn.kgc.util.SystemConstant;
import cn.kgc.util.resultutil.ResultConstant;
import cn.kgc.util.resultutil.exception.HttpException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @author YC
 */
@RestController
@RequestMapping("/users")
@Api(tags = "用户管理接口")
@Validated
@Slf4j
@CrossOrigin
public class UsersController {

    @Resource
    private UsersService usersService;
    @Resource
    private DeptsService deptsService;
    @Resource
    private RolesService rolesService;
    @Resource
    private MenusService menusService;

    /**
     * 获取登录用户的路由信息和按钮权限信息
     *
     * @return 路由信息和权限信息map
     */
    @GetMapping("/info")
    @ApiOperation(value = "获取登录用户的路由信息和按钮权限信息")
    public Map<String, Object> info() {
        // 获得用户的路由信息
        List<RouterVo> routerVoList = menusService.getRouterVoList();
        // 获得用户的按钮权限信息
        return Map.of(
                "allRouters", routerVoList,
                "buttonPerms", menusService.getMenuPerms()
        );
    }

    /**
     * 删除用户信息（包含批量删除）
     * 使用@CacheEvict注解 表示方法触发缓存逐出
     * 使用@Caching注解 允许多个嵌套@Cacheable、@CachePut、@CacheEvict注释可以用于相同的方法
     *
     * @param map 要删除的用户id集合
     * @return 删除结果
     */
    @DeleteMapping("/deleteByIds")
    @Caching(evict = {
            @CacheEvict(value = "users", key = "'detail' + #map.get('userIds')"),
            @CacheEvict(value = "users", key = "'selectAll'")
    })
    @ApiOperation(value = "删除用户信息（包含批量删除）")
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(@RequestBody HashMap<String, Integer[]> map) {
        //TODO: 登录功能完成后获取当前登录用户id
        Integer loginUserId = 1;
        List<Integer> userIds = List.of(map.get("userIds"));
        // 不允许自删
        if (userIds.contains(loginUserId)) {
            throw new HttpException(ResultConstant.USER_DELETE_ERROR_SELF);
        }
        // 不允许删除部门主管
        for (Integer userId : userIds) {
            LambdaQueryWrapper<Depts> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Depts::getUserId, userId);
            if (deptsService.count(wrapper) > 0) {
                throw new HttpException(ResultConstant.USER_DELETE_ERROR_LEADER);
            }
        }
        // 不允许删除管理员
        for (Integer userId : userIds) {
            Users users = usersService.getById(userId);
            if (users != null) {
                if (users.getRoleId() == SystemConstant.USER_ADMIN_ROLE_ID) {
                    throw new HttpException(ResultConstant.USER_DELETE_ERROR_ADMIN);
                }
            }
        }
        // 删除操作
        return usersService.removeByIds(userIds);
    }

    /**
     * 查看用户信息详情
     * 使用@Cacheable注解表示方法触发缓存填充
     * key = "#root.methodName" 使用方法名作为缓存的key
     * sync = true 表示开启同步，当多个请求同时进入时，只有一个请求去数据库拿数据，其他请求等待缓存同步
     * condition = "条件表达式" 表示满足什么条件才开启缓存
     *
     * @param id 用户id
     * @return 用户实例
     */
    @GetMapping("/detail/{id}")
    @ApiOperation(value = "查看用户信息详情")
    @Cacheable(value = "users#360", key = "#root.methodName + #id")
    public Users detail(@PathVariable("id") Integer id) {
        return usersService.getById(id);
    }

    /**
     * 添加用户信息
     *
     * @param form 新增表单
     * @return 新增结果
     */
    @PostMapping("/save")
    @ApiOperation(value = "添加用户信息")
    public boolean save(@RequestBody @Valid UsersAddForm form) {
        //TODO 用户名不能重复
        Users users = new Users();
        BeanUtils.copyProperties(form, users);
        //TODO 密码加密
        return usersService.save(users);
    }

    /**
     * 使用@CachePut注解 表示在不干扰方法执行的情况下更新缓存
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新用户信息")
    @CachePut(value = "users#360", key = "'detail' + #form.userId")
    public Users update(@RequestBody UsersUpdateForm form) {
        Integer userId = form.getUserId();
        // 用户名不能重复
        checkUserName(form.getUserName(), userId);
        // 不重复则更新信息
        Users users = usersService.getById(userId);
        if (users != null) {
            BeanUtil.copyProperties(form, users);
            usersService.updateById(users);
        }
        return users;
    }

    /**
     * 分页查询用户信息
     *
     * @param params 分页参数（pageNum pageSize userName mobile state deptId roleId）
     * @return 封装后的对象
     */
    @GetMapping("/list")
    @ApiOperation(value = "分页查询用户信息")
    public Pager<Users> selectPage(@RequestBody HashMap<String, Object> params) {
        Integer pageNum = MapUtil.getInt(params, "pageNum");
        Integer pageSize = MapUtil.getInt(params, "pageSize");
        String userName = MapUtil.getStr(params, "userName");
        String mobile = MapUtil.getStr(params, "mobile");
        Integer state = MapUtil.getInt(params, "state");
        Integer deptId = MapUtil.getInt(params, "deptId");
        Integer roleId = MapUtil.getInt(params, "roleId");

        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.likeRight(StrUtil.isNotBlank(userName), Users::getUserName, userName)
                .eq(StrUtil.isNotBlank(mobile), Users::getMobile, mobile)
                .eq(state != 0, Users::getState, state)
                .eq(deptId != 0, Users::getDeptId, deptId)
                .eq(roleId != 0, Users::getRoleId, roleId);
        Page<Users> page = new Page<>(pageNum, pageSize);
        Pager<Users> pager = Pager.build(usersService.page(page, wrapper));
        pager.getCurrentPageRecords().forEach(user -> {
            int tempId = user.getRoleId();
            Roles roles = rolesService.getById(tempId);
            if (roles != null) {
                user.setRoleName(roles.getRoleName());
            }
        });
        return pager;

    }

    //==================================== 接口中使用的自定义方法 ===================================

    /**
     * 检查用户名是否重复
     */
    private void checkUserName(String userName, int userId) {
        LambdaQueryWrapper<Users> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Users::getUserName, userName)
                // ne方法排除当前
                .ne(Users::getUserId, userId);
        if (usersService.count(wrapper) > 0) {
            throw new HttpException(ResultConstant.USER_UPDATE_ERROR_REPEAT);
        }
    }

}
